Crackme 08 by ReptileCrackeR
[zip]
- Type de la protection
: nom / numéro de série
- Méthode utilisée
: keygening
- Outils utilisés
:
On perd pas de temps,
le programme est compressé avec UPX (voir tutz sur le crackme d'hErmol
pour vous rafraîchir la mémoire), on le décompresse vite fait, et on ouvre
avec OllyDbg. Clic-droit, 'Search for', 'All referenced text strings',
on voit la chaîne "Sorry " en remontant un peu, on double-clique, et nous
voilà à un endroit très intéressant. J'espère que pour vous ceci est devenu
presque comme un réflexe. On ne voit pas explicitement les appels aux
API car c'est codé en Delphi, mais on s'y retrouve quand même, vous verrez.
On remonte.
00454B49 |> 837D E8 01 ....CMP
DWORD PTR SS:[EBP-18],1
00454B4D |. 75 35 .........JNZ SHORT Crackme8.00454B84
00454B4F |. 68 644C4500 ...PUSH Crackme8.00454C64
.........; ASCII "Thanks "
00454B54 |. 8D55 C8 .......LEA EDX,DWORD
PTR SS:[EBP-38]
00454B57 |. 8B45 FC .......MOV EAX,DWORD
PTR SS:[EBP-4]
00454B5A |. 8B80 F0020000 .MOV EAX,DWORD
PTR DS:[EAX+2F0]
00454B60 |. E8 D7F0FDFF ...CALL Crackme8.00433C3C
00454B65 |. FF75 C8 .......PUSH DWORD PTR
SS:[EBP-38]
00454B68 |. 68 744C4500 ...PUSH Crackme8.00454C74
.........;
ASCII ", code a keygen now !"
00454B6D |. 8D45 CC .......LEA EAX,DWORD
PTR SS:[EBP-34]
00454B70 |. BA 03000000 ...MOV EDX,3
00454B75 |. E8 46FAFAFF ...CALL Crackme8.004045C0
00454B7A |. 8B45 CC .......MOV EAX,DWORD
PTR SS:[EBP-34]
00454B7D |. E8 9A8EFDFF ...CALL Crackme8.0042DA1C
00454B82 |. EB 33 .........JMP SHORT Crackme8.00454BB7
00454B84 |> 68 944C4500 ...PUSH Crackme8.00454C94
.........;
ASCII "Sorry "
00454B89 |. 8D55 C0 .......LEA EDX,DWORD
PTR SS:[EBP-40]
00454B8C |. 8B45 FC .......MOV EAX,DWORD
PTR SS:[EBP-4]
00454B8F |. 8B80 F0020000 .MOV EAX,DWORD
PTR DS:[EAX+2F0]
00454B95 |. E8 A2F0FDFF ...CALL Crackme8.00433C3C
00454B9A |. FF75 C0 .......PUSH DWORD PTR
SS:[EBP-40]
00454B9D |. 68 A44C4500 ...PUSH Crackme8.00454CA4
.........;
ASCII ", bad serial !"
On voit l'appel de
la bonne MessageBox, de plus en plus intéressant.
Au-dessus quelques tests, on monte, on monte et on voit que la routine
commence en 004549E0, posons donc un breakpoint !
On exécute le prog avec F9, on entre nom et numéro, on clique sur le bouton,
et ça breake, arf.
Etudions le code maintenant. Je vais pas décrire toutes les lignes, mais
les plus importantes pour aller plus vite.
00454A0C |. BA
144C4500
...MOV
EDX,Crackme8.00454C14 ......;
ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345.."
En 00454A0C
le programme charge une chaîne "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"...
00454A22 |. E8 15F2FDFF
..CALL Crackme8.00433C3C
00454A27 |. 837D E0 00 ...CMP DWORD PTR SS:[EBP-20],0
00454A2B |. 75 0F ... ....JNZ
SHORT Crackme8.00454A3C
00454A2D |. 8D45 F0 ......LEA EAX,DWORD PTR
SS:[EBP-10]
00454A30 |. BA 444C4500 ..MOV EDX,Crackme8.00454C44
.......;
ASCII "xxxxxxxxxxxxxxxxxxxx"
Ensuite en 454A27
on vérifie si on a rentré un nom, sinon on indique que le nom entré est
"xxxxxxxxxxxxxxxxxxxx".
On charge ensuite le nom et le numéro.
00454A61 |. E8 9AFAFAFF ..
..CALL
Crackme8.00404500
00454A66 |. 83F8 14 ......
..CMP
EAX,14
00454A69 |. 75 13 ........
..JNZ
SHORT Crackme8.00454A7E
00454A6B |. 8D55 F8 ......
..LEA
EDX,DWORD PTR SS:[EBP-8]
00454A6E |. 8B45 FC ......
..MOV
EAX,DWORD PTR SS:[EBP-4]
00454A71 |. 8B80 F4020000
..
MOV
EAX,DWORD PTR DS:[EAX+2F4]
00454A77 |. E8 C0F1FDFF ..
..CALL
Crackme8.00433C3C
00454A7C |. EB 0D .......
...JMP
SHORT Crackme8.00454A8B
00454A7E |> 8D45 F8 .....
...LEA
EAX,DWORD PTR SS:[EBP-8]
00454A81 |. BA 444C4500 ..
..MOV
EDX,Crackme8.00454C44 .......s;
ASCII "xxxxxxxxxxxxxxxxxxx"
Puis en 00454A66 on
regarde si le nombre de caractères pour le numéro est de 20 (0x14 en hexadécimal),
si ce n'est pas le cas on remplace le numéro entré par "xxxxxxxxxxxxxxxxxxxx".
Donc dans ce crackme on sait déjà qu'il faut rentré un nom (mais ça on
s'en doutait déjà), et que le numéro de série doit être de 20 caractères.
00454A9F |. E8 5CFAFAFF
..
..CALL
Crackme8.00404500
00454AA4 |. 83F8 14
..
..
..
CMP
EAX,14
00454AA7 |. 7E 1B
..
..
..
..JLE
SHORT Crackme8.00454AC4
00454AA9 |. 8D55 D4
..
..
..
LEA
EDX,DWORD PTR SS:[EBP-2C]
00454AAC |. 8B45 FC
..
..
..
MOV
EAX,DWORD PTR SS:[EBP-4]
00454AAF |. 8B80 F0020000
..
MOV
EAX,DWORD PTR DS:[EAX+2F0]
00454AB5 |. E8 82F1FDFF
..
..CALL
Crackme8.00433C3C
00454ABA |. 8B45 D4
..
..
..
MOV
EAX,DWORD PTR SS:[EBP-2C]
00454ABD |. E8 3EFAFAFF
..
..CALL
Crackme8.00404500
00454AC2 |. EB 05
..
..
..
..JMP
SHORT
Crackme8.00454AC9
00454AC4 |> B8 14000000
..
..MOV
EAX,14
Le programme
compare ensuite le nombre de caractères du nom avec 20 (ou 0x14), si on
a plus de 20 caractères, on entre ce nombre dans EAX, sinon, EAX est à
20, ce qui nous servira de compteur pour boucler ensuite. Pour l'instant
notre nom fait moins de 20 caractères, nous verrons pourquoi après.
Vient ensuite la routine de génération du numéro.
Mais ici le programme ne fera pas la comparaison entre les 2
chaînes à la fin, il fait la comparaison caractère par caractère, et mettra
un boléen (variable qui ne peut être que VRAI ou FAUX) à VRAI si finalement
le numéro correspond, voici donc la routine commentée :
00454AC4 |> B8 14000000
..
..MOV
EAX,14 .....................;
on initialise la boucle à 20 passages
00454AC9 |> 33DB ..
....
....XOR
EBX,EBX ....................;
EBX = 0
00454ACB |. 33F6 ..
....
....XOR
ESI,ESI ....................;
ESI = 0
00454ACD |. 85C0 ..
....
....TEST
EAX,EAX
00454ACF |. 7E 78 ..
....
...JLE
SHORT Crackme8.00454B49
00454AD1 |. 8945 E4 ..
....
.MOV
DWORD PTR SS:[EBP-1C],EAX ..; valeur qui
nous servira de compteur
00454AD4 |. C745 EC 01000000 MOV DWORD PTR SS:[EBP-14],1.....;
il s'agit de la valeur qui permettra
00454ADB |> 43 ..
....
....
.INC
EBX ; EBX = EBX + 1.........;
de savoir le nombre
de passage effectué
00454ADC |. 46 ..
....
....
.INC
ESI ; ESI = ESI + 1
00454ADD |. 8B45 F0 ..
....
.MOV
EAX,DWORD PTR SS:[EBP-10] ..;
on charge le nom
00454AE0 |. 33D2 ..
....
....XOR
EDX,EDX ; EDX = 0
00454AE2 |. 8A5418 FF ..
....MOV
DL,BYTE PTR DS:[EAX+EBX-1] .;
on met dans DL un caractère du nom
00454AE6 |. 8B45 EC ..
....
.MOV
EAX,DWORD PTR SS:[EBP-14]
00454AE9 |. 8D0440 ..
....
..LEA
EAX,DWORD PTR DS:[EAX+EAX*2] ; EAX = 3 x nombre de passage fait
00454AEC |. 03D0 ..
....
....ADD
EDX,EAX ....................;
EDX = EDX + EAX
00454AEE |. B8 64000000 ..
..MOV
EAX,64 .....................;
nous allons boucler 100 fois (0x64)
00454AF3 |> 83FA 24 ..
....
.CMP
EDX,24
00454AF6 |. 7E 03 ..
....
...JLE
SHORT Crackme8.00454AFB ....;
si EDX > 36 (0x24)
00454AF8 |. 83EA 24 ..
....
.SUB
EDX,24 .....................;
on soustrait 36 à EDX
00454AFB |> 48 ..
....
....
.DEC
EAX
00454AFC |.^75 F5 ..
....
...JNZ
SHORT Crackme8.00454AF3
00454AFE |. 8B45 F8 ..
....
.MOV
EAX,DWORD PTR SS:[EBP-8] ...;
on charge le numéro entré
00454B01 |. 8A4430 FF ..
....MOV
AL,BYTE PTR DS:[EAX+ESI-1] .;
on prend un caractère
00454B05 |. 8B4D F4 ..
....
.MOV
ECX,DWORD PTR SS:[EBP-C] ...;
on charge la chaîne "ABC..."
00454B08 |. 3A4411 FF ..
....CMP
AL,BYTE PTR DS:[ECX+EDX-1] .;
on le compare avec l'un de la chaîne
00454B0C |. 75 08 .
.....
...JNZ
SHORT Crackme8.00454B16 ....;
"ABC..." à la position EDX
00454B0E |. 8B45 E8 .
.....
.MOV
EAX,DWORD PTR SS:[EBP-18]...;
si la lettre = la valeur booléenne
00454B11 |. 8945 E8 .
.....
.MOV
DWORD PTR SS:[EBP-18],EAX ..;
ne change pas
00454B14 |. EB 05 .
.....
...JMP
SHORT Crackme8.00454B1B
00454B16 |> 33C0 .
.....
....XOR
EAX,EAX ....................;
sinon on met le booléen à FAUX
00454B18 |. 8945 E8 .
.....
.MOV
DWORD PTR SS:[EBP-18],EAX ..;
donc numéro entré invalide
00454B1B |> 8D55 D0 .
.....
.LEA
EDX,DWORD PTR SS:[EBP-30]
00454B1E |. 8B45 FC .
.....
.MOV
EAX,DWORD PTR SS:[EBP-4]
00454B21 |. 8B80 F0020000 .
.MOV
EAX,DWORD PTR DS:[EAX+2F0]
00454B27 |. E8 10F1FDFF .
...CALL
Crackme8.00433C3C
00454B2C |. 8B45 D0 .
.....
.MOV
EAX,DWORD PTR SS:[EBP-30]
00454B2F |. E8 CCF9FAFF .
...CALL
Crackme8.00404500 .........;
on compte le nbre de car. du nom entré
00454B34 |. 3BD8 .
.....
....CMP
EBX,EAX ....................;
si on est arrivé au dernier car. du nom
00454B36 |. 75 02 .
.....
...JNZ
SHORT Crackme8.00454B3A ....;
on recommence avec la 1ère lettre du nom
00454B38 |. 33DB .
.....
....XOR
EBX,EBX
00454B3A |> 83FE 14 .
.....
.CMP
ESI,14
00454B3D |. 75 02 .
.....
...JNZ
SHORT Crackme8.00454B41
00454B3F |. 33F6 .
.....
....XOR
ESI,ESI
00454B41 |> FF45 EC .
.....
.INC
DWORD PTR SS:[EBP-14] ......;
on incrémente le nbre de passages fait
00454B44 |. FF4D E4 .
.....
.DEC
DWORD PTR SS:[EBP-1C] ......;
on décrémente le nbre de passag. à faire
00454B47 |.^75 92 .
.....
...JNZ
SHORT Crackme8.00454ADB ....;
a-t-on fini de vérifier le numéro ?
Avec ces renseignements
on peut à présent faire le keygener :
int nbr, nbre_passage_restant, nbre_passage_fait,
posN, posS, posC;
char name[20];
char serie[21];
char chaine[40]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
nbr=GetDlgItemText(hwndDlg, IDC_EDIT1, name, 21);
if (nbr==20)
SetDlgItemText (hwndDlg, IDC_EDIT1, name);
nbre_passage_restant = 20;
nbre_passage_fait = 1;
posN = 0;
posS = 0;
do
{
posN++;
posS++;
posC = 0;
posC = (int) name[posN - 1];
posC += 3*nbre_passage_fait;
while (posC > 36)
posC -= 36;
serie[posS - 1] = chaine[posC - 1];
if (posN==nbr)
posN = 0;
nbre_passage_fait++;
nbre_passage_restant--;
}
while (nbre_passage_restant != 0);
SetDlgItemText (hwndDlg, IDC_EDIT2, serie);
Vous avez sûrement
remarqué que je n'ai pas commenté le code entre 00454B3A et 00454B3F, tout
simplement parce que c'est un bug du programme, étudions ça quand même,
ça ne coûte rien, c'est bonus.
Le principe pour l'instant est que si nous avons entré un nom de moins de
20 caractères, nous bouclerons donc sur le nom afin de générer le numéro,
c'est-à-dire qu'arrivé à la fin du nom, on reviendra au début, d'où la ligne
00454B38. Mais si on entre un nom de plus de 20 caractères nous ne bouclerons
pas 20 fois, mais autant de fois qu'il y a de lettres dans le nom entré.
Or :
00454B3A |> 83FE
14 .
.... .
.CMP
ESI,14
00454B3D |. 75 02 .
.... .
...JNZ
SHORT Crackme8.00454B41
00454B3F |. 33F6 .
.... .
.... XOR
ESI,ESI
nous indique
que si nous en sommes à notre 20ème passage, le caractère à vérifier du
numéro entré revient à 0.
Pour la génération du numéro ça pose pas de problème, mais si on entre le
numéro ainsi généré, le crackme ne le prendra pas valide, et pourquoi ?
Eh bien en bouclant de la sorte sur le numéro, on a écrasé le 1er numéro
et/ou plus, et donc lors de la vérification, le numéro n'est plus bon.
Prenons un exemple : Le_MaLaDe/G85QDVJTT7ZWH4MAKKYQ impeccable,
notre nom fait moins de 20 caractères. Avec le keygener créé on entre par
exemple : Le_MaLaDe - ShmeitCorp et nous obtenons :
Le_MaLaDe - ShmeitCo/G85QDVJTTZF5NBJELZP0
Si nous tenions compte exactement de la vérification, nous aurions sans
troncature :
Le_MaLaDe - ShmeitCorp/675QDVJTTZF5NBJELZP0
Nous pouvons voir que les 2 premiers chiffres des numéros de série sont
différents, qui correspondent aux 2 caractères supplémentaires.
En effet le fait de boucler sur le numéro de série a remplacé les anciens
numéros qui étaient corrects pour les 1ers caractères du nom, par des numéros
qui sont corrects pour les derniers caractères, et donc quand le programme
voudra vérifier les premiers caractères, eh bien ça ne correspondra plus.
Enfin je ne sais pas si j'ai été clair, mais pour moi ça l'est... donc c'est
pour cela qu'on ne prendra en compte que 20 caractères pour le nom.
|